package com.ctg.itrdc.sysmgr.portal.service.impl;

import java.sql.Timestamp;
import java.util.List;
import java.util.Random;
import java.util.concurrent.TimeUnit;

import javax.annotation.Resource;

import com.ctg.itrdc.pasp.core.exception.CodedException;
import com.ctg.itrdc.sysmgr.portal.data.ISystemPasswordRuleDao;
import com.ctg.itrdc.sysmgr.portal.data.ISysuserPasswordHisDao;
import com.ctg.itrdc.sysmgr.portal.data.entity.SystemPasswordRule;
import com.ctg.itrdc.sysmgr.portal.data.entity.SysuserPasswordHis;
import com.ctg.itrdc.sysmgr.portal.service.utils.PasswordHelper;
import com.sun.tools.javac.jvm.Code;
import org.apache.commons.codec.binary.Base64;
import org.apache.commons.codec.digest.DigestUtils;
import org.apache.commons.collections.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import com.alibaba.fastjson.JSON;
import com.ctg.itrdc.pasp.context.service.BaseService;
import com.ctg.itrdc.pasp.core.PageInfo;
import com.ctg.itrdc.sysmgr.portal.api.dto.SystemUserDTO;
import com.ctg.itrdc.sysmgr.portal.api.service.ISystemUserService;
import com.ctg.itrdc.sysmgr.portal.data.ISystemUserDao;
import com.ctg.itrdc.sysmgr.portal.data.entity.SystemUser;
import com.ctg.itrdc.sysmgr.portal.data.vo.SystemUserVO;
import com.ctg.itrdc.sysmgr.portal.service.utils.BeanUtils;

@Component("systemUserService")
public class SystemUserServiceImpl extends
        BaseService<SystemUser, Long, SystemUserDTO> implements
        ISystemUserService {

    @Resource
    private ISystemUserDao systemUserDao;

    @Resource
    private ISysuserPasswordHisDao sysuserPasswordHisDao;

    @Resource
    private ISystemPasswordRuleDao systemPasswordRuleDao;

    @Value("${password.algorithmName}")
    private String algorithmName;

    @Value("${password.hashIterations}")
    private int hashIterations;

    protected Logger logger = LoggerFactory.getLogger(this.getClass());

    @Override
    public PageInfo selectByOrgId(SystemUserDTO dto, int currentPage,
                                  int perPageNum) {

        SystemUser entity = BeanUtils
                .applyIfNotException(dto, SystemUser.class);
        Long orgId = dto.getOrgId();
        if (orgId == null) {
            return this.queryPageInfo(dto, currentPage, perPageNum);
        }
        PageInfo pageInfo = systemUserDao.selectByOrgId(entity, orgId,
                currentPage, perPageNum);
        List<?> list = pageInfo.getList();
        List<SystemUserDTO> dtoList = BeanUtils.copyListNotException(list,
                SystemUserDTO.class);
        pageInfo.setList(dtoList);
        return pageInfo;
    }

    @Override
    @SuppressWarnings("unchecked")
    public SystemUserDTO findUserByLoginName(String sysUserCode) {

        SystemUserDTO systemUserDTO = new SystemUserDTO();
        systemUserDTO.setSysUserCode(sysUserCode);
        List<SystemUserDTO> systemUserDTOList = this
                .selectByExample(systemUserDTO);
        if (systemUserDTOList.size() < 1) {
            return null;
        }

        systemUserDTO = systemUserDTOList.get(0);
        SystemUserDTO tmp = BeanUtils.applyIfNotException(systemUserDTO,
                SystemUserDTO.class);
        tmp.setPassword("******");
        logger.debug("find SystemUser from DB,param:sysUserCode:{},result:{}",
                sysUserCode, JSON.toJSONString(tmp, true));

        return systemUserDTO;
    }

    @Override
    public String resetPassword(SystemUserDTO dto) {
        dto = selectByPrimaryKey(dto);
        String password = genRandomString(6);
        // dto.setPassword(password);
        // dto.setPwdNewtime(DateUtils.dateToTimestamp(new Date()));
        // sysmgrBaseService.updateByPrimaryKey(dto); //
        // 由于同类里只会生成一个事务，造成AOP无法拦截，所以避免同类内部调用
        return password;
    }

    private String genRandomString(int strLen) {
        Random random = new Random();
        byte[] bytes = new byte[strLen];
        random.nextBytes(bytes);
        try {
            return new String(Base64.encodeBase64(bytes)).substring(0, strLen);

        } catch (Exception e) {
            // TODO Auto-generated catch block
        }
        return "";
        // return RandomStringUtils.random(strLen);
    }

    @Override
    public void updateLoginNum(Long sysUserId) {

        SystemUserDTO systemUserDTO = new SystemUserDTO();
        systemUserDTO.setSysUserId(sysUserId);
        SystemUserDTO tmp = this.selectByPrimaryKey(systemUserDTO);
        if (tmp != null) {
            Integer loginedNum = 1;
            if (tmp.getLoginedNum() != null) {
                loginedNum = tmp.getLoginedNum() > 0 ? tmp.getLoginedNum() + 1
                        : 1;
            }
            systemUserDTO.setLoginedNum(loginedNum);
            super.updateSelectiveByPrimaryKey(systemUserDTO);
        }
        // sysmgrBaseService.updateNotNullFieldsByPrimaryKey(systemUserDTO);
    }

    @SuppressWarnings("all")
    @Override
    public PageInfo<SystemUserDTO> excludeByIds(SystemUserDTO dto,
                                                List<Long> idList, int currentPage, int perPageNum) {
        if (dto == null)
            dto = new SystemUserDTO();
        SystemUserVO entity = BeanUtils.applyIfNotException(dto,
                SystemUserVO.class);
        PageInfo pageInfo = systemUserDao.excludeByIds(entity, idList,
                currentPage, perPageNum);
        List list = pageInfo.getList();
        if (CollectionUtils.isNotEmpty(list)) {
            List<SystemUserDTO> dtoList = BeanUtils.copyListNotException(list,
                    SystemUserDTO.class);
            pageInfo.setList(dtoList);
        }
        return pageInfo;
    }

    @SuppressWarnings("all")
    @Override
    public PageInfo<SystemUserDTO> includeByIds(SystemUserDTO dto,
                                                List<Long> idList, int currentPage, int perPageNum) {
        if (CollectionUtils.isNotEmpty(idList)) {
            SystemUserVO entity = null;
            if (dto != null) {
                entity = BeanUtils.applyIfNotException(dto, SystemUserVO.class);
            }
            PageInfo pageInfo = systemUserDao.includeByIds(entity, idList,
                    currentPage, perPageNum);
            List list = pageInfo.getList();
            if (CollectionUtils.isNotEmpty(list)) {
                List<SystemUserDTO> dtoList = BeanUtils.copyListNotException(
                        list, SystemUserDTO.class);
                pageInfo.setList(dtoList);
            }
            return pageInfo;
        }
        return new PageInfo<>();
    }

    public int validatedUser(SystemUserDTO user) {
        String username = user.getSysUserCode();
        String password = user.getPassword();

        // 用户名不存在
        if (findUserByLoginName(username) == null) {
            return 0;
        }
        byte[] md5Bytes = DigestUtils.md5(password.getBytes());
        String encodePassword = Base64.encodeBase64String(md5Bytes);
        SystemUser entity = new SystemUser();
        entity.setSysUserCode(username);
        entity.setPassword(encodePassword);
        List<SystemUser> res = systemUserDao.selectByExample(entity);
        if (res.size() == 0) {
            return -1;
        }

        return 1;
    }

    @Transactional
    public int deleteByPrimaryKey(SystemUserDTO dto) {
        return super.deleteByPrimaryKey(dto);
    }

    @Transactional
    public int deleteByPrimaryKey(Long id) {
        return super.deleteByPrimaryKey(id);
    }

    @Transactional
    public int[] batchDeleteByPrimaryKey(List<SystemUserDTO> list) {
        return batchDeleteByPrimaryKey(list);
    }

    @Override
    public int updatePassword(String sysUserCode, String password, String oldPassword) {
        SystemUserDTO user = findUserByLoginName(sysUserCode);
        if (user == null) {
            throw new CodedException("404", sysUserCode);
        }
        String encryptPassword = encrypt(oldPassword);
        if (!StringUtils.equals(encryptPassword, user.getPassword())) {
            throw new CodedException("402", sysUserCode);
        }
        String encrypt = encrypt(password);
        checkPasswordRule(user, password, encrypt);
        SystemUser dto = new SystemUser();
        dto.setId(user.getId());
        dto.setPassword(encrypt);
        Timestamp now = new Timestamp(System.currentTimeMillis());
        dto.setUpdateDate(now);
        dto.setPwdNewtime(now);
        dto.setPassNeedModify(false);
        savePasswordHistory(user.getId(), encrypt);
        return getDao().updateSelectiveByPrimaryKey(dto);
    }

    @Override
    public int updateWithPassword(SystemUserDTO dto, String password) {
        if(password == null){
            return super.updateSelectiveByPrimaryKey(dto);
        }
        String encryptPassword = encrypt(password);
        checkPasswordRule(dto, password, encryptPassword);
        dto.setPassword(encryptPassword);
        if(dto.getPassRuleId() == null){
            dto.setPassRuleId(-1L);
        }
        int i = super.updateSelectiveByPrimaryKey(dto);
        savePasswordHistory(dto.getId(), encryptPassword);
        return i;
    }

    private String encrypt(String oldPassword) {
        return PasswordHelper.encryptPassword(oldPassword, algorithmName, hashIterations);
    }

    private void checkPasswordRule(SystemUserDTO user, String password, String encryptPassword) {
        Long passRuleId = user.getPassRuleId();
        if (passRuleId == null) {
            return;
        }
        SystemPasswordRule rule = systemPasswordRuleDao.selectByPrimaryKey(passRuleId);
        if (rule == null) {
            return;
        }
        String pattern = rule.getPattern();
        if (pattern != null && !password.matches(pattern)) {
            throw new CodedException("405", pattern);
        }
        Integer reuseIntervalDays = rule.getReuseIntervalDays();
        SysuserPasswordHis last = null;
        try {
            last = sysuserPasswordHisDao.getBySqlId("selectLastByPassword", new Object[]{user.getId(), encryptPassword});
        } catch (Exception e) {
            return;
        }
        if (reuseIntervalDays != null) {
            if (last != null && System.currentTimeMillis() - last.getCreateDate().getTime() < TimeUnit.DAYS.toMillis(reuseIntervalDays)) {
                throw new CodedException("407", reuseIntervalDays);
            }
        }

        Integer reuseIntervalNums = rule.getReuseIntervalNums();
        if (reuseIntervalNums != null && last != null) {
            Long count = sysuserPasswordHisDao.countBySqlId("countAfterLast", null, new Object[]{user.getId(), last.getCreateDate()});
            if (count < reuseIntervalNums) {
                throw new CodedException("408", reuseIntervalNums);
            }
        }
    }

    @Override
    public Long insert(SystemUserDTO dto) {
        Long id = super.insert(dto);
        String password = dto.getPassword();
        savePasswordHistory(id, password);
        return id;
    }

    private void savePasswordHistory(Long id, String password) {
        SysuserPasswordHis entity = new SysuserPasswordHis();
        entity.setPassword(password);
        entity.setSysUserId(id);
        Timestamp now = new Timestamp(System.currentTimeMillis());
        entity.setCreateDate(now);
        entity.setUpdateDate(now);
        sysuserPasswordHisDao.insert(entity);
    }

}
